package org.jlambda;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


final public class Context {

	static public class PlaceHolder {
	}
	static public class DerivedPlaceHolder extends PlaceHolder {
	}
	public static final PlaceHolder _ = new PlaceHolder();

	/**
	 * There are a tonne of thread handling solutions out there,
	 * java concurrent is in j2se (and used as default impl) but
	 * j2ee is handled by container, usually either JCA or CommonJ.
	 * 
	 * Since the common thread is Runnables, thats what we use.
	 * 
	 * @author TGDTWCH1
	 *
	 */
	public static interface BackgroundExecutor {
		public void execute(Runnable task);
		public void stop();
	};

	public static int StartPool = 5;
	public static int MaxPool = 5;
	public static int Timeout = 360; // seconds
	public static TimeUnit Unit = TimeUnit.SECONDS; // seconds
	public static BlockingQueue Queue = new LinkedBlockingQueue();
	
	/**
	 * Only ever call this in start up code, preferably just for j2ee servers.
	 * 
	 * Call before any active tasks have been run.
	 *  
	 * @param newExecutor
	 */
	public static void replaceExecutor(BackgroundExecutor newExecutor){
		lazyHolder.executor.stop();
		lazyHolder.executor = newExecutor;
	}
	
	/**
	 * Allows the actual executor to be created lazily.  Startpool etc can
	 * be manipulated and then upon the first executor usage it will create it.
	 * 
	 * NOTE this form of singleton is garunteed by the jls.
	 * 
	 * @author Chris
	 *
	 */
	private static class lazyHolder {
		private static BackgroundExecutor executor = new DefaultBackgroundExecutor();
		
	}
	
	public static BackgroundExecutor getExecutor(){
		return lazyHolder.executor;
	}
	
	/**
	 * By default, the Queue is a LinkedBlockingQueue and only the StartPool size has an impact.
	 * 
	 * All starting threads are created.
	 * 
	 * NOTE you will see worse performance for small background tasks if you have more threads. This
	 * is due to the contention on the BlockingQueues taking longer then the actual work on the thread.
	 * 
	 * This suggests two things: a) don't put small tasks in applyBg's, b) choose a reasonable number of threads
	 * for the particular application
	 * 
	 * In general to fine tune a given group of background functions you can supply a BackgroundExecutor
	 * to the applyBg function as its first parameter.
	 * 
	 */
	public static class DefaultBackgroundExecutor implements BackgroundExecutor {
		final ThreadPoolExecutor executor;
		public DefaultBackgroundExecutor(int startPool, int maxPool, long timeout, TimeUnit unit, BlockingQueue queue){
			executor = new ThreadPoolExecutor(startPool, maxPool, timeout, unit, queue);
			executor.prestartAllCoreThreads();
		}
		DefaultBackgroundExecutor(){
			this(StartPool, MaxPool, Timeout, Unit, Queue);
		}
		public void execute(Runnable task) {
			executor.execute(task);
		}
		public void stop() {
			executor.shutdownNow();
		}
		
	}
		
}
